home *** CD-ROM | disk | FTP | other *** search
- {****************************************************************************}
- {* *}
- {* O V E R L A Y H . P A S - Overlay Handler *}
- {* *}
- {****************************************************************************}
-
- {****************************************************************************}
- {* *}
- {* Released to the public domain *}
- {* *}
- {****************************************************************************}
-
- {****************************************************************************
- * O V E R L A Y H . P A S R E V I S I O N H I S T O R Y
- * $Revision: 1.0 $
- * $Log: D:/PASCAL/TURBO/SST/UI/VCS/OVERLAYH.PAV $
- *
- * Rev 1.0 09 Jan 1990 17:21:58
- * Initial revision.
- *
- ****************************************************************************}
-
- {****************************************************************************
- * +-------------+
- * Author: Roy Furman [72346,72] | M O D U L E |
- * Date: January, 1990 +-------------+
- *
- **************
- * SYNOPSIS: Handler to manage overlays loaded onto the heap.
- *
- * DESCRIPTION: This unit allows an application to control loading and
- * unloading of Turbo Pascal 5.5 overlays onto the standard heap rather than
- * into the overlay buffer managed by the Overlay unit supplied with Turbo
- * Pascal. By allowing the program to explicitly load and unload overlays,
- * routines that normally would not be a candidate for an overlay can be
- * made into overlays and loaded when needed. For instance, an application
- * with many time-critical hardware device drivers, only one, or a few, of
- * which will actually be used during program execution, normally must not
- * overlay the drivers to insure memory residency during interrupt service
- * calls. These routines can now be made into overlays and selectively
- * loaded onto the heap during device initialization where they will remain
- * resident until explictly unloaded under program control.
- *
- * To prepare a unit for overlaying onto the heap requires no special
- * considerations beyond those needed by the standard Overlay unit. The
- * Overlay unit must be initialized by a call to OvrInit before any routines
- * in OverlayHandler are used.
- *
- * Only two procedures are interfaced: LoadOverlay and UnloadOverlay. Each
- * is supplied with an address parameter of any procedure or function that
- * is interfaced by the unit to overlay. The address supplied is only used
- * to locate the overlay descriptor segment built by the compiler. The unit
- * that contains the passed address will be loaded into the free space of
- * the heap. Once loaded, it can be called freely. The unit will remain
- * heap-resident until it is explicitly freed by an UnloadOverlay call.
- *
- * An overlay unit on the heap will be ignored by Turbo's Overlay manager.
- * When the overlay unit is not on the heap, it will be managed by the Overlay
- * unit in the conventional fashion. If a heap overlay is released that has
- * returns to one of its routines still pending in the stack, the stack will
- * be patched to enable Turbo's Overlay handler to reload the overlay into
- * the overlay buffer when the return occurs. The heap space used by
- * Load/UnloadOverlay is otherwise exclusive of the overlay buffer space.
- * Both procedures return a result code in ovrLoadResult.
- *
- * OverlayHandler.LoadOverlay works by first insuring that the requested
- * unit is an overlay and that it is not in memory, or will not be reloaded
- * into memory by an outstanding procedure/function return. If sufficient
- * memory to load the overlay code, fixup table, and a 15 byte buffer exists,
- * then space is allocated on the heap and the overlay descriptor is patched
- * with the paragraph boundary to load the overlay. The overlay is read into
- * the heap by calling OvrReadBuf in the Overlay unit. If there are no errors,
- * the space required for the fixup table is released and the overlay
- * descriptor jump table is patched with "jmp far" instructions to the new
- * entry points.
- *
- * OverlayHandler.UnloadOverlay first insures that the unit request was
- * loaded by LoadOverlay before it patches any outstanding stack returns to
- * return to the overlay descriptor jump table. The jump table is then
- * changed from "jmp far" instructions to "int 3f" instructions and the
- * overlay is marked as unloaded. The heap space allocated to the code is
- * then returned to the free list.
- *
- *
- * Limitations:
- *
- * An overlay unit that is in Turbo's overlay buffer or that has stack
- * returns into the overlay pending cannot be loaded onto the heap. In the
- * former case, call Overlay.OvrClearBuf to unload all units from the buffer,
- * and then call OverlayHandler.LoadOverlay to load onto the heap.
- *
- * An overlay that requires more than 65521 bytes for code, the fixup table,
- * and a 15 byte overhead for paragraph alignment cannot be loaded because
- * the heap allocation routines do not allow a larger request.
- *
- * The OverlayHandler unit, itself, may be an overlay, but it cannot load
- * itself onto the heap. If it is attempted, an error will be returned.
- *
- * These routines only work with Turbo Pascal 5.5. The technique should
- * also work with version 5.0 as the overlay descriptor segments are similar,
- * but a work-alike replacement for the call Overlay.OvrReadBuf would need
- * to be developed.
- ****************************************************************************}
-
- {.$O+,F+}
- unit OverlayHandler;
- interface
- uses Overlay;
-
- const
- ovrLoadOk = 0; { Load/UnloadOverlay - no errors }
- ovrLoadNotOverlay = -1; { unit is not an overlay }
- ovrLoadInUse = -2; { overlay is currently loaded }
- ovrLoadWaitRet = -3; { stack return to overlay is pending }
- ovrLoadSizeErr = -4; { overlay space request > 65521 bytes }
- ovrLoadNoMemory = -5; { requested space is not available }
- ovrLoadReadErr = -6; { error reading overlay }
- ovrLoadNotLoaded = -7; { overlay is in memory already }
- ovrLoadNotHeap = -8; { overlay loaded by Overlay unit }
- ovrLoadSelfErr = -9; { cannot load OverlayHandler on heap }
-
- var
- ovrLoadResult : Integer; { Result code for overlay request }
-
- procedure LoadOverlay (AnyRoutine : Pointer);
- { Load an overlay onto the heap }
- procedure UnloadOverlay (AnyRoutine : Pointer);
- { Unload an overlay from the heap }
-
- implementation
-
- type
- jumpVectors = record
- case Integer of
- 1 : (instr : Byte; { jmp far addr if overlay loaded }
- addrs : Pointer);
- 2 : (jmpfar : Byte;
- adrOfs : Word;
- adrSeg : Word);
- 3 : (int3f : Word; { int 3f offset }
- offset : Word;{ offset of entry point }
- nul : Byte);
- end { jumpVectors } ;
-
- vectorTable = array [1..13097] of jumpVectors;
-
- OverlayNodePtr = ^OverlayNode;
- OverlayNode = record { overlay descriptor record }
- OvrInst : Word; { overlay interrupt }
- ovSaveReturn : Word; { offset into jump vector }
- ovFilePos : LongInt; { offset of overlay in OVR file }
- ovCodeSize : Word; { size of code overlay }
- ovFixupSize : Word; { size of relocation information }
- ovJmpCount : Word; { # of entries in ovVectors }
- ovLink : Word; { rel segment addr of next OvrCodeList }
- ovSegment : Word; { current address of segment }
- ovRetryCount : Word; { 1 if overlay reprieved }
- ovNext : Word; { abs segment addr for next OvrLoadList }
- ovEmsPage : Word; { page address }
- ovEmsOffset : Word; { offset within page }
- ovArea : Pointer; { normally not used. Heap area ptr }
- ovNotUsed : Word;
- ovVectors : vectorTable;
- end { OverLayNode } ;
-
- var
- OvrBP : Word; { stack frame ptr to start addr search }
-
- function PatchStackSegs(oldCS, newCS : Word) : Word;
- { Probe the stack for return segment addresses equaling oldCS and replace
- with newCS. Return the frame pointer (BP) of the first segment address
- replaced or return 0 if no active returns to oldCS were replaced. }
- var bp, return : Word;
- begin
- return := 0;
- bp := OvrBP; { point to top stack frame }
- while bp <> 0 do begin { 0 marks last stack frame }
- if MemW[SSeg:bp+4] = oldCS then begin
- MemW[SSeg:bp+4] := newCS; { replace segment of return address }
- if return = 0 then
- return := bp; { save frame pointer of 1st replacement }
- end { if } ;
- bp := MemW[SSeg:bp]; { link down to next stack frame }
- end { while } ;
- PatchStackSegs := return; { return frame pointer, if any }
- end { PatchStackSegs } ;
-
- function PatchStackFrames(oldCS, newCS, newIP : Word) : Word;
- { Replace all stack return addresses with segments equaling oldCS with
- newCS. Replace the return address of the first stack frame
- matching oldCS:xxxx with newCS:newIP. Return the replaced oldIP or
- return 0 if no active returns to oldCS are found }
- var bp : Word;
- begin
- bp := PatchStackSegs(oldCS, newCS);{ patch return segment addresses }
- if bp <> 0 then begin
- PatchStackFrames := MemW[SSeg:bp+2];
- MemW[SSeg:bp+2] := newIP; { patch return offset address }
- end { if }
- else
- PatchStackFrames := 0;
- end { PatchStackFrames } ;
-
- procedure ovVectorReturn (OvrSeg : Word);
- { Replace stack returns to ovSegment with returns to OvrSeg,
- and replace first return to Overlay Manager by saving original ip.
- Replace "jmp far" with "int 3f" in jump vector table. }
- var
- p : OverlayNodePtr;
- i, temp : Word;
- begin
- p := Ptr(OvrSeg, 0); { form overlay descriptor pointer }
- p^.ovSaveReturn := PatchStackFrames(p^.ovSegment, OvrSeg, 0);
- { Replace all jump vectors with traps to overlay manager }
- for i := 1 to p^.ovJmpCount do
- with p^.ovVectors[i] do begin
- temp := adrOfs; { save offset of routine's entry }
- int3f := $3FCD; { replace jmp far with int 3fh }
- offset := temp; { store entry offset }
- nul := 0; { clear byte following }
- end { with } ;
- end { ovVectorReturn } ;
-
- procedure LinkovVectors (OvrSeg : Word);
- { Link new entry points in ovVectors.
- Convert int 3f/offset to jmp far ovSegment:offset entries. }
- var
- p : OverlayNodePtr;
- i, temp, newSeg : Word;
- begin
- p := Ptr(OvrSeg, 0); { form overlay descriptor pointer }
- newSeg := p^.ovSegment; { load address }
- { Replace all traps to overlay manager with jmp far's }
- for i := 1 to p^.ovJmpCount do
- with p^.ovVectors[i] do begin
- temp := offset; { save offset of routine's entry }
- instr := $EA; { replace int 3fh with jmp far }
- addrs := Ptr(newSeg, temp);
- end { with } ;
- end { LinkovVectors } ;
-
- function BPtr : Word;
- { Return stack frame offset }
- Inline($8B/$C5 { mov ax,bp } );
-
-
- { ---------------- P U B L I C P R O C E D U R E S -------------------- }
-
- procedure LoadOverlay (AnyRoutine : Pointer);
- { Load an overlay onto the heap }
- var
- p : OverlayNodePtr;
- spaceNeeded : LongInt;
- pMemory : Pointer;
- begin
- p := Ptr(Seg(AnyRoutine^), 0); { form overlay descriptor pointer }
-
- {$IFOPT O+}
- if Seg(p^) = Seg(LoadOverlay) then begin
- ovrLoadResult := ovrLoadSelfErr;
- Exit;
- end { if } ;
- {$ENDIF}
- if p^.ovrInst <> $3FCD then begin { not an overlay descriptor }
- ovrLoadResult := ovrLoadNotOverlay;
- Exit;
- end { if } ;
- if (p^.ovSegment <> 0) or (p^.ovVectors[1].instr = $EA)then begin
- ovrLoadResult := ovrLoadInUse; { overlay is already in memory }
- Exit;
- end { if } ;
- if p^.ovSaveReturn <> 0 then begin { waiting return to overlay }
- ovrLoadResult := ovrLoadWaitRet;
- Exit;
- end { if } ;
-
- spaceNeeded := ((p^.ovCodeSize+15) shr 4 + (p^.ovFixupSize+15) shr 4) shl 4
- + 15;
- if spaceNeeded > 65521 then begin { requested space too large }
- ovrLoadResult := ovrLoadSizeErr;
- Exit;
- end { if } ;
- if spaceNeeded > MaxAvail then begin { requested memory not available }
- ovrLoadResult := ovrLoadNoMemory;
- Exit;
- end { if } ;
- GetMem(pMemory, spaceNeeded); { request allocation }
- if Ofs(pMemory^) = 0 then
- p^.ovSegment := Seg(pMemory^) { load at paragraph boundary }
- else
- p^.ovSegment := Seg(pMemory^)+1; { load at nearest paragraph boundary }
-
- if OvrReadBuf(Seg(p^)) <> 0 then begin { read overlay into memory }
- FreeMem(pMemory, spaceNeeded); { release overlay memory }
- ovrLoadResult := ovrLoadReadErr; { overlay file read error }
- Exit;
- end { if } ;
-
- p^.ovArea := pMemory; { save overlay load location }
- if p^.ovFixupSize <> 0 then begin { free fixup memory }
- pMemory := Ptr(p^.ovSegment + (p^.ovCodeSize+15) shr 4, 0);
- FreeMem(pMemory, ((p^.ovFixupSize+15) shr 4) shl 4 + 15-Ofs(p^.ovArea^));
- end { if } ;
-
- LinkovVectors(Seg(p^)); { patch ovVectors }
- ovrLoadResult := ovrLoadOk;
- end { LoadOverlay } ;
-
- procedure UnloadOverlay(AnyRoutine : Pointer);
- { Unload an overlay from the heap }
- var
- p, q : OverlayNodePtr;
- spaceNeeded : LongInt;
- pMemory : Pointer;
- begin
- p := Ptr(Seg(AnyRoutine^), 0); { form overlay descriptor pointer }
-
- {$IFOPT O+}
- if Seg(p^) = Seg(UnloadOverlay) then begin
- ovrLoadResult := ovrLoadSelfErr;
- Exit;
- end { if } ;
- {$ENDIF}
- if p^.ovrInst <> $3FCD then begin { not an overlay descriptor }
- ovrLoadResult := ovrLoadNotOverlay;
- Exit;
- end { if } ;
- if (p^.ovSegment = 0) or (p^.ovVectors[1].instr <> $EA)then begin
- ovrLoadResult := ovrLoadNotLoaded;{ overlay is not in memory }
- Exit;
- end { if } ;
- if p^.ovSaveReturn <> 0 then begin { waiting return to overlay }
- ovrLoadResult := ovrLoadWaitRet;
- Exit;
- end { if } ;
- if OvrLoadList <> 0 then begin { search Overlay unit list of overlays }
- q := Ptr(OvrLoadList, 0); { point to list of loaded overlays }
- repeat
- if Seg(q^) = Seg(p^) then begin
- ovrLoadResult := ovrLoadNotHeap;
- Exit;
- end { if } ;
- q := Ptr(q^.ovNext, 0);
- until q = nil;
- end { if } ;
- if p^.ovArea = nil then begin
- ovrLoadResult := ovrLoadNotHeap;
- Exit;
- end { if } ;
-
- ovrBP := BPtr; { start stack search here }
- ovVectorReturn(Seg(p^)); { patch ovVectors/stack returns }
- p^.ovSegment := 0; { mark as unloaded }
- FreeMem(p^.ovArea, ((p^.ovCodeSize+15) shr 4) shl 4 + Ofs(p^.ovArea^));
- p^.ovArea := nil;
- ovrLoadResult := ovrLoadOk;
- end { UnloadOverlay } ;
-
- end { OverlayHandler } .
-
-